package com.smc.common.utils;

import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;
import com.smc.common.exception.ServiceException;


/**
 * @author zouqinghua
 * @date 2018年12月4日  下午3:47:11
 *
 */
public class PoolUtils {

	private static final Logger logger = LoggerFactory.getLogger(PoolUtils.class);
	
	public static void executeTask(List<Runnable> commands){
		if(CollectionUtils.isEmpty(commands)){
			return ;
		}
		int poolSize = Runtime.getRuntime().availableProcessors();
		ThreadPoolExecutor executor =
	            new ThreadPoolExecutor(poolSize,
	            		poolSize * 2, 0L, TimeUnit.MILLISECONDS,
	                    new LinkedBlockingQueue<Runnable>());
		logger.info("executeTask start poolSize = {}---------------------",poolSize);
		Stopwatch stopwatch = Stopwatch.createStarted();
		for (Runnable command : commands) {
			executor.execute(command);
		}
		
		executor.shutdown();
		while (!executor.isTerminated()) {
			 try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					logger.error("sleep",e);
				}	
		 }
		
		long millis =stopwatch.stop().elapsed(TimeUnit.MILLISECONDS);
		logger.info("executeTask end 耗时：{}ms, poolSize = {}, commands.size = {}----------------------",millis,poolSize,commands.size());
		
		
	}
	
	public static <E>List<E> executeCallableTask(List<Callable> commands) throws InterruptedException, ExecutionException{
		if(CollectionUtils.isEmpty(commands)){
			return null;
		}
		List<E> list = Lists.newArrayList();
		List<Future> resultList = Lists.newArrayList();
		int poolSize = 100+Runtime.getRuntime().availableProcessors();
		ThreadPoolExecutor executor =
	            new ThreadPoolExecutor(poolSize,
	            		poolSize * 2+100, 0L, TimeUnit.MILLISECONDS,
	                    new LinkedBlockingQueue<Runnable>());
		logger.info("executeTask start poolSize = {}---------------------",poolSize);
		Stopwatch stopwatch = Stopwatch.createStarted();
		
		for (Callable command : commands) {
			Future result = executor.submit(command);
            resultList.add(result);
		}
		executor.shutdown();
		try {
			for (Future future : resultList) {
				E object = (E)future.get();
				if(object!=null){
					list.add(object);
				}
			}
		} catch (InterruptedException | ExecutionException e) {
			logger.error("executeCallableTask error ",e);
			executor.shutdownNow();
			throw new ServiceException("executeCallableTask 多线程查询异常 error "+e.getMessage());
		}
		long millis =stopwatch.stop().elapsed(TimeUnit.MILLISECONDS);
		logger.info("executeTask end 耗时：{}ms, poolSize = {}, commands.size = {}, list.size = {} ----------------------",millis,poolSize,commands.size(),list.size());
		return list;
	}
	
	public static <E>List<E> executeCallableTaskByGroup(List<Callable> commands){
		if(CollectionUtils.isEmpty(commands)){
			return null;
		}
		List<E> list = Lists.newArrayList();
		
		int poolSize = 10+Runtime.getRuntime().availableProcessors();
		ThreadPoolExecutor executor =
	            new ThreadPoolExecutor(poolSize,
	            		poolSize * 2, 0L, TimeUnit.MILLISECONDS,
	                    new LinkedBlockingQueue<Runnable>());
		logger.info("executeTask start poolSize = {}---------------------",poolSize);
		Stopwatch stopwatch = Stopwatch.createStarted();
		List<Future> resultList = Lists.newArrayList();
		for (Callable command : commands) {
			Future result = executor.submit(command);
            resultList.add(result);
		}
		executor.shutdown();
		try {
			for (Future future : resultList) {
				List<E> objects = (List<E>) future.get();
				if(CollectionUtils.isNotEmpty(objects)){
					list.addAll(objects);
					//String md5 = FileUtils.getMd5(objects);
					//logger.info("commands_md5:{}, size = {}",md5,objects.size());
					//System.err.println("commands_md5: "+md5);
				}
			}
		} catch (InterruptedException | ExecutionException e) {
			logger.error("executeCallableTaskByGroup error ",e);
			executor.shutdownNow();
			throw new ServiceException("executeCallableTaskByGroup 多线程查询异常 error "+e.getMessage());
		}
		
		long millis =stopwatch.stop().elapsed(TimeUnit.MILLISECONDS);
		logger.info("executeTask end 耗时：{}ms, poolSize = {}, commands.size = {}, list.size = {} ----------------------",millis,poolSize,commands.size(),list.size());
		
		
		return list;
	}
}
